﻿using mozhi.smarterp.Finance.Accounts;
using mozhi.smarterp.Finance.Accounts.Repository;
using mozhi.smarterp.Finance.Basedatas.Customers;
using mozhi.smarterp.Finance.Basedatas.Employees;
using mozhi.smarterp.Finance.Basedatas.Events;
using mozhi.smarterp.Finance.Basedatas.Repository;
using mozhi.smarterp.Finance.Querys;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.Guids;
using Volo.Abp.ObjectMapping;

namespace mozhi.smarterp.Finance.Basedatas
{
    public class EmployeeAppService : BaseDataAppService<Employee, EmployeeDto, EmployeeCreateDto, EmployeeUpdateDto>, IEmployeeAppService
    {
        private IAccountRepository _accountRepository;

        public EmployeeAppService(IBaseDataRepository<Employee> repository, IDataAssociationRepository dataAssociationRepository, IGuidGenerator guidGenerator , 
            IDistributedEventBus distributedEventBus , IAccountRepository accountRepository) 
            : base(repository, dataAssociationRepository, guidGenerator,distributedEventBus)
        {
            _accountRepository = accountRepository;
        }

        public override async Task<PagedResultDto<EmployeeDto>> FindAsync(PageQuery query)
        {
            var result =await base.FindAsync(query);

            var employees = result.Items.ToList();

            if (employees == null || employees.Count == 0)
                return result;

            await LoadAccountInfoAsync(employees);

            return result;

        }

        public override async Task<EmployeeDto> CreateAsync(EmployeeCreateDto dto)
        {
            await Validate(null, dto.Code, dto.Name);

            await ValidateAccount(dto.CurrentAccountId);

            var employee = new Employee(_guidGenerator.Create(), dto.Code, dto.Name , dto.CurrentAccountId);

            employee = await _repository.InsertAsync(employee);

            var result = ObjectMapper.Map<Employee, EmployeeDto>(employee);

            await LoadAccountInfoAsync(new List<EmployeeDto>() { result });

            return result;
        }

        public override async Task<EmployeeDto> UpdateAsync(EmployeeUpdateDto dto)
        {
            var employee = await _repository.GetAsync(dto.Id);

            if (employee == null)
                throw new UserFriendlyException("员工不存在", "100000");

            await Validate(dto.Id, dto.Code, dto.Name);

            await ValidateAccount(dto.CurrentAccountId);

            employee.Change(dto.Code, dto.Name , dto.Activated);
            employee.ChangeAccount(dto.CurrentAccountId);

            employee = await _repository.UpdateAsync(employee);

            var result = ObjectMapper.Map<Employee, EmployeeDto>(employee);

            await LoadAccountInfoAsync(new List<EmployeeDto>() { result });

            return result;
        }

        public override async Task<EmployeeDto> DeleteAsync(Guid id)
        {
            var employee = await base.DeleteAsync(id);

            await _distributedEventBus.PublishAsync(new DataAssociationRemoveEvent(id, employee.CurrentAccountId));

            return employee;
        }

        #region
        private async Task LoadAccountInfoAsync(List<EmployeeDto> employees)
        {
            var accountIds = employees.Where(x => x.CurrentAccountId != default).Select(x => x.CurrentAccountId).Distinct().ToList();

            if (accountIds.Count == 0)
                return;

            var accounts = await _accountRepository.FindAsync(new AccountQuery() { Ids = accountIds });


            foreach (var employee in employees)
            {
                employee.CurrentAccountName = accounts.FirstOrDefault(x => x.Id == employee.CurrentAccountId)?.FullName;
            }
        }


        private async Task ValidateAccount(Guid currentAccountId)
        {
            var accounts = await _accountRepository.FindAsync(new AccountQuery() { Ids = new List<Guid> { currentAccountId } });

            var matchCurrentAccount = accounts.FirstOrDefault(x => x.Id == currentAccountId);

            base.ValidateAccount(matchCurrentAccount, "往来科目");
        }
        #endregion
    }
}
